﻿using JNPF.Basics.Logic;
using JNPF.Basics.Models;
using JNPF.Basics.Models.Permission.Dtos.AuthorizeData;
using JNPF.Basics.Models.Permission.Model;
using JNPF.Utils;
using JNPF.Utils.Controller;
using Microsoft.AspNetCore.Mvc;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace JNPF.Basics.Controller
{
    /// <summary>
    /// 操作权限
    /// 版 本：V3.0.0
    /// 版 权：引迈信息技术有限公司（https://www.jnpfsoft.com）
    /// 作 者：JNPF开发平台组
    /// 日 期：2017.11.07
    /// </summary>
    [Route("api/Permission/[controller]")]
    public class AuthorizeController : BaseApiController
    {
        private AuthorizeBll authorizeBll = new AuthorizeBll();
        private UserOnlineBll userOnlineBll = new UserOnlineBll();
        private UserRelationBll userRelationBll = new UserRelationBll();

        #region GET
        /// <summary>
        /// 获取功能权限数据
        /// </summary>
        /// <param name="itemId"></param>
        /// <param name="objectType"></param>
        /// <returns></returns>
        [HttpGet("Model/{itemId}/{objectType}")]
        public async Task<ResponseResult> GetModelList(string itemId, string objectType)
        {
            var entityList = await authorizeBll.GetAuthorizeModelList(itemId, objectType);
            var ids = entityList.Select(x => x.ObjectId).ToList();
            return Success(new { ids });
        }
        #endregion

        #region POST
        /// <summary>
        /// 权限数据
        /// </summary>
        /// <param name="objectId">对象主键</param>
        /// <param name="input">参数</param>
        /// <returns></returns>
        [HttpPost("Data/{objectId}/Values")]
        public async Task<ResponseResult> GetDataValues(string objectId, [FromBody] AuthorizeDataQuery input)
        {
            var output = new AuthorizeDataOutput();
            #region 权限数据来源
            var authorizeData = await authorizeBll.GetAuthorize();
            var menuList = authorizeData.ModuleList.MapToList<ModuleEntity>();
            var moduleButtonList = authorizeData.ButtonList.MapToList<ModuleButtonEntity>();
            var moduleColumnList = authorizeData.ColumnList.MapToList<ModuleColumnEntity>();
            var moduleDataSchemeList = authorizeData.ResourceList.MapToList<ModuleDataAuthorizeSchemeEntity>();
            #endregion
            #region 已勾选的权限id
            var authorizeList = await authorizeBll.GetListByObjectId(objectId);
            var checkModuleList = authorizeList.Where(o => o.ItemType.Equals("module")).Select(m => m.ItemId).ToList();
            var checkButtonList = authorizeList.Where(o => o.ItemType.Equals("button")).Select(m => m.ItemId).ToList();
            var checkColumnList = authorizeList.Where(o => o.ItemType.Equals("column")).Select(m => m.ItemId).ToList();
            var checkResourceList = authorizeList.Where(o => o.ItemType.Equals("resource")).Select(m => m.ItemId).ToList();
            #endregion
            //勾选的菜单数据
            var moduleList = new List<ModuleEntity>();
            var childNodesIds = new List<string>();
            switch (input.type)
            {
                case "module":
                    var authorizeDataModuleList = authorizeData.ModuleList.MapToList<AuthorizeDataOutputModel>();
                    GetOutPutResult(ref output, authorizeDataModuleList, checkModuleList);
                    return Success(output);
                case "button":
                    if (string.IsNullOrEmpty(input.moduleIds))
                    {
                        return Success(output);
                    }
                    else
                    {
                        var moduleIdList = new List<string>(input.moduleIds.Split(","));
                        moduleIdList.ForEach(ids =>
                        {
                            var moduleEntity = menuList.Find(m => m.Id == ids);
                            if (moduleEntity != null)
                            {
                                moduleList.Add(moduleEntity);
                            }
                        });
                        //勾选的菜单末级节点菜单id集合
                        childNodesIds = GetChildNodesId(moduleList);
                    }
                    output = GetButton(moduleList, moduleButtonList, childNodesIds, checkButtonList);
                    return Success(output);
                case "column":
                    if (string.IsNullOrEmpty(input.moduleIds))
                    {
                        return Success(output);
                    }
                    else
                    {
                        var moduleIdList = new List<string>(input.moduleIds.Split(","));
                        moduleIdList.ForEach(ids =>
                        {
                            var moduleEntity = menuList.Find(m => m.Id == ids);
                            if (moduleEntity != null)
                            {
                                moduleList.Add(moduleEntity);
                            }
                        });
                        //子节点菜单id集合
                        childNodesIds = GetChildNodesId(moduleList);
                    }
                    output = GetColumn(moduleList, moduleColumnList, childNodesIds, checkColumnList);
                    return Success(output);
                case "resource":
                    if (string.IsNullOrEmpty(input.moduleIds))
                    {
                        return Success(output);
                    }
                    else
                    {
                        var moduleIdList = new List<string>(input.moduleIds.Split(","));
                        moduleIdList.ForEach(ids =>
                        {
                            var moduleEntity = menuList.Find(m => m.Id == ids);
                            if (moduleEntity != null)
                            {
                                moduleList.Add(moduleEntity);
                            }
                        });
                        //子节点菜单id集合
                        childNodesIds = GetChildNodesId(moduleList);
                    }
                    output = GetResource(moduleList, moduleDataSchemeList, childNodesIds, checkResourceList);
                    return Success(output);
                default:
                    return Success(output);
            }
        }

        /// <summary>
        /// 设置或更新岗位/角色/用户权限
        /// </summary>
        /// <param name="objectId">参数</param>
        /// <param name="input">参数</param>
        /// <returns></returns>
        [HttpPut("Data/{objectId}")]
        public async Task<ResponseResult> UpdateData(string objectId, [FromBody] AuthorizeDataUpInput input)
        {
            input.button = input.button.Except(input.module).ToList();
            input.column = input.column.Except(input.module).ToList();
            input.resource = input.resource.Except(input.module).ToList();
            var authorizeList = new List<AuthorizeEntity>();
            AddAuthorizeEntity(ref authorizeList, input.module, input.objectType, "module");
            AddAuthorizeEntity(ref authorizeList, input.button, input.objectType, "button");
            AddAuthorizeEntity(ref authorizeList, input.column, input.objectType, "column");
            AddAuthorizeEntity(ref authorizeList, input.resource, input.objectType, "resource");
            await authorizeBll.Save(objectId, authorizeList);
            #region 清除缓存
            var onlineUserIds = (await userOnlineBll.GetList()).Select(x => x.userId).ToList();
            var roleUserIds = (await userRelationBll.GetListByObjectId(objectId)).Select(x => x.UserId).ToList();
            foreach (var item in onlineUserIds)
            {
                if (roleUserIds.Contains(item))
                {
                    await userOnlineBll.Delete(item);
                    CacheFactory.Cache.Remove(CacheKey.USERAUTHORIZE + item);
                }
            }
            #endregion
            return Success("操作成功");
        }

        /// <summary>
        /// 批量设置权限
        /// </summary>
        /// <param name="input">参数</param>
        /// <returns></returns>
        [HttpPost("Data/Batch")]
        public async Task<ResponseResult> BatchData([FromBody] AuthorizeDataBatchInput input)
        {
            input.button = input.button.Except(input.module).ToList();
            input.column = input.column.Except(input.module).ToList();
            input.resource = input.resource.Except(input.module).ToList();
            var authorizeItemList = new List<AuthorizeEntity>();
            var authorizeObejctList = new List<AuthorizeEntity>();
            BatchAddAuthorizeEntity(ref authorizeItemList, input.module, "module", true);
            BatchAddAuthorizeEntity(ref authorizeItemList, input.button, "button", true);
            BatchAddAuthorizeEntity(ref authorizeItemList, input.column, "column", true);
            BatchAddAuthorizeEntity(ref authorizeItemList, input.resource, "resource", true);
            BatchAddAuthorizeEntity(ref authorizeObejctList, input.positionIds, "Position", false);
            BatchAddAuthorizeEntity(ref authorizeObejctList, input.roleIds, "Role", false);
            BatchAddAuthorizeEntity(ref authorizeObejctList, input.userIds, "User", false);
            await authorizeBll.SaveBatch(authorizeObejctList, authorizeItemList);
            return Success("操作成功");
        }

        /// <summary>
        /// 设置/更新功能权限
        /// </summary>
        /// <param name="itemId"></param>
        /// <param name="input"></param>
        /// <returns></returns>
        [HttpPut("Model/{itemId}")]
        public async Task<ResponseResult> UpdateModel(string itemId, [FromBody] AuthorizeModelInput input)
        {
            await authorizeBll.UpdateModel(itemId, input);
            return Success("操作成功");
        }
        #endregion

        #region Method
        /// <summary>
        /// 按钮权限
        /// </summary>
        /// <param name="moduleList">选中的菜单</param>
        /// <param name="moduleButtonList">所有的菜单</param>
        /// <param name="childNodesIds"></param>
        /// <param name="checkList"></param>
        /// <returns></returns>
        private AuthorizeDataOutput GetButton(List<ModuleEntity> moduleList, List<ModuleButtonEntity> moduleButtonList, List<string> childNodesIds, List<string> checkList)
        {
            var output = new AuthorizeDataOutput();
            var buttonList = new List<ModuleButtonEntity>();
            childNodesIds.ForEach(ids =>
            {
                var buttonEntity = moduleButtonList.FindAll(m => m.ModuleId == ids);
                if (buttonEntity.Count != 0)
                {
                    buttonEntity.ForEach(bt =>
                    {
                        if (bt.ParentId.Equals("-1"))
                        {
                            bt.ParentId = ids;
                        }
                    });
                    buttonList = buttonList.Union(buttonEntity).ToList();
                }
            });
            var authorizeDataButtonList = buttonList.MapToList<AuthorizeDataOutputModel>();
            var authorizeDataModuleList = new List<AuthorizeDataOutputModel>();
            //末级菜单id集合
            var moduleIds = buttonList.Select(b => b.ModuleId).ToList().Distinct().ToList();
            GetParentsModuleList(moduleIds, moduleList, ref authorizeDataModuleList);
            var list = authorizeDataModuleList.Union(authorizeDataButtonList).ToList();
            GetOutPutResult(ref output, list, checkList);
            return output;
        }

        /// <summary>
        /// 列表权限
        /// </summary>
        /// <param name="moduleList"></param>
        /// <param name="moduleColumnEntity"></param>
        /// <param name="childNodesIds"></param>
        /// <param name="checkList"></param>
        /// <returns></returns>
        private AuthorizeDataOutput GetColumn(List<ModuleEntity> moduleList, List<ModuleColumnEntity> moduleColumnEntity, List<string> childNodesIds, List<string> checkList)
        {
            var output = new AuthorizeDataOutput();
            var columnList = new List<ModuleColumnEntity>();
            childNodesIds.ForEach(ids =>
            {
                var columnEntity = moduleColumnEntity.FindAll(m => m.ModuleId == ids);
                if (columnEntity.Count != 0)
                {
                    columnEntity.ForEach(bt =>
                    {
                        bt.ParentId = ids;
                    });
                    columnList = columnList.Union(columnEntity).ToList();
                }
            });
            var authorizeDataColumnList = columnList.MapToList<AuthorizeDataOutputModel>();
            var authorizeDataModuleList = new List<AuthorizeDataOutputModel>();
            var moduleIds = columnList.Select(b => b.ModuleId).ToList().Distinct().ToList();
            GetParentsModuleList(moduleIds, moduleList, ref authorizeDataModuleList);
            var list = authorizeDataModuleList.Union(authorizeDataColumnList).ToList();
            GetOutPutResult(ref output, list, checkList);
            return output;
        }

        /// <summary>
        /// 数据权限
        /// </summary>
        /// <param name="moduleList"></param>
        /// <param name="moduleResourceEntity"></param>
        /// <param name="childNodesIds"></param>
        /// <param name="checkList"></param>
        /// <returns></returns>
        private AuthorizeDataOutput GetResource(List<ModuleEntity> moduleList, List<ModuleDataAuthorizeSchemeEntity> moduleResourceEntity, List<string> childNodesIds, List<string> checkList)
        {
            var moduleIds = new List<string>();
            var output = new AuthorizeDataOutput();
            var authorizeDataResourceList = new List<AuthorizeDataOutputModel>();
            childNodesIds.ForEach(ids =>
            {
                var resourceEntity = moduleResourceEntity.FindAll(m => m.ModuleId == ids);
                if (resourceEntity.Count != 0)
                {
                    moduleIds.Add(ids);
                    var entity = resourceEntity.MapToList<AuthorizeDataOutputModel>();
                    entity.ForEach(e =>
                    {
                        e.parentId = ids;
                    });
                    authorizeDataResourceList = authorizeDataResourceList.Union(entity).ToList();
                }
            });
            var authorizeDataModuleList = new List<AuthorizeDataOutputModel>();
            GetParentsModuleList(moduleIds, moduleList, ref authorizeDataModuleList);
            var list = authorizeDataModuleList.Union(authorizeDataResourceList).ToList();
            GetOutPutResult(ref output, list, checkList);
            return output;
        }

        /// <summary>
        /// 获取子节点菜单id
        /// </summary>
        /// <param name="moduleEntitiesList"></param>
        /// <returns></returns>
        private List<string> GetChildNodesId(List<ModuleEntity> moduleEntitiesList)
        {
            var ids = moduleEntitiesList.Select(m => m.Id).ToList();
            var pids = moduleEntitiesList.Select(m => m.ParentId).ToList();
            var childNodesIds = ids.Where(x => !pids.Contains(x) && moduleEntitiesList.Find(m => m.Id == x).ParentId != "-1").ToList();
            return childNodesIds.Union(ids).ToList();
        }

        /// <summary>
        /// 返回参数处理
        /// </summary>
        /// <param name="output">返回参数</param>
        /// <param name="list">返回参数数据</param>
        /// <param name="checkList">已勾选的id</param>
        /// <param name="parentId"></param>
        private void GetOutPutResult(ref AuthorizeDataOutput output, List<AuthorizeDataOutputModel> list, List<string> checkList, string parentId = "-1")
        {
            output.all = list.Select(l => l.id).ToList();
            output.ids = checkList;
            output.list = list.ToTree(parentId);
        }

        /// <summary>
        /// 添加权限接口参数组装
        /// </summary>
        /// <param name="list">返回参数</param>
        /// <param name="itemIds">权限数据id</param>
        /// <param name="objectType">分类</param>
        /// <param name="itemType">权限分类</param>
        private void AddAuthorizeEntity(ref List<AuthorizeEntity> list, List<string> itemIds, string objectType, string itemType)
        {
            foreach (var item in itemIds)
            {
                var entity = new AuthorizeEntity();
                entity.ItemId = item;
                entity.ItemType = itemType;
                entity.ObjectType = objectType;
                list.Add(entity);
            }
        }

        /// <summary>
        /// 批量添加权限接口参数组装
        /// </summary>
        /// <param name="list">返回参数</param>
        /// <param name="ids">来源数据</param>
        /// <param name="type">来源类型</param>
        /// <param name="isData">是否是权限数据</param>
        private void BatchAddAuthorizeEntity(ref List<AuthorizeEntity> list, List<string> ids, string type, bool isData)
        {
            if (ids != null && ids.Count != 0)
            {
                if (isData)
                {
                    foreach (var item in ids)
                    {
                        var entity = new AuthorizeEntity();
                        entity.ItemId = item;
                        entity.ItemType = type;
                        list.Add(entity);
                    }
                }
                else
                {
                    foreach (var item in ids)
                    {
                        var entity = new AuthorizeEntity();
                        entity.ObjectId = item;
                        entity.ObjectType = type;
                        list.Add(entity);
                    }
                }
            }
        }

        /// <summary>
        /// 过滤菜单权限数据
        /// </summary>
        /// <param name="childNodesIds">其他权限数据菜单id集合</param>
        /// <param name="moduleList">勾选菜单权限数据</param>
        /// <param name="output">返回值</param>
        private void GetParentsModuleList(List<string> childNodesIds, List<ModuleEntity> moduleList, ref List<AuthorizeDataOutputModel> output)
        {
            //获取有其他权限的菜单末级节点id
            var authorizeModuleData = moduleList.MapToList<AuthorizeDataOutputModel>();
            foreach (var item in childNodesIds)
            {
                GteModuleListById(item, authorizeModuleData, output);
            }
            output = output.Distinct().ToList();
        }

        /// <summary>
        /// 根据菜单id递归获取authorizeDataOutputModel的父级菜单
        /// </summary>
        /// <param name="id">菜单id</param>
        /// <param name="authorizeDataOutputModel">选中菜单集合</param>
        /// <param name="output">返回数据</param>
        private void GteModuleListById(string id, List<AuthorizeDataOutputModel> authorizeDataOutputModel, List<AuthorizeDataOutputModel> output)
        {
            var data = authorizeDataOutputModel.Find(l => l.id == id);
            if (data != null)
            {
                if (data.parentId != "-1")
                {
                    if (!output.Contains(data))
                    {
                        output.Add(data);
                    }
                    GteModuleListById(data.parentId, authorizeDataOutputModel, output);
                }
                else
                {
                    if (!output.Contains(data))
                    {
                        output.Add(data);
                    }
                }
            }
        }
        #endregion
    }
}
